package cn.sh.yhk.acl.service;


import cn.hutool.core.bean.BeanUtil;
import cn.sh.yhk.acl.mapper.PermissionMapper;
import cn.sh.yhk.acl.mapper.RoleMapper;
import cn.sh.yhk.acl.mapper.RolePermissionMapper;
import cn.sh.yhk.acl.mapper.UserRoleMapper;
import cn.sh.yhk.acl.po.PermissionPo;
import cn.sh.yhk.acl.po.RolePermissionPo;
import cn.sh.yhk.acl.po.RolePo;
import cn.sh.yhk.acl.po.UserRolePo;
import cn.sh.yhk.acl.vo.PermissionVo;
import cn.sh.yhk.acl.vo.RoloVo;
import cn.sh.yhk.acl.vo.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PermissionServiceImpl implements PermissionService {
    @Autowired
    UserInfoService userInfoService;
    @Autowired
    UserRoleMapper userRoleMapper;
    @Autowired
    RolePermissionMapper rolePermissionMapper;
    @Autowired
    PermissionMapper permissionMapper;
    @Autowired
    RoleMapper roleMapper;

    @Override
    @Transactional
    public List<PermissionVo> selectPermissionByUserId(Integer id) {
        UserInfoVo user = userInfoService.selectUserWithRoleById(id);
        List<RolePermissionPo> rpids = rolePermissionMapper.selectList(new LambdaQueryWrapper<RolePermissionPo>()
                .in(RolePermissionPo::getRid, user.getRoleList().stream().map(RolePo::getId).toList()));
        List<PermissionPo> permissionPoList = permissionMapper.selectBatchIds(rpids.stream()
                .map(RolePermissionPo::getPid).collect(Collectors.toList()));
        List<PermissionVo> voList = BeanUtil.copyToList(permissionPoList, PermissionVo.class);
        return getTreePermission(voList);
    }


    @Override
    @Transactional
    public List<PermissionVo> selectPermissionByRoleId(Integer roleId) {
        //所有菜单
        List<PermissionPo> sourcelist = permissionMapper.selectList(new LambdaQueryWrapper<>());
        List<PermissionVo> voList = BeanUtil.copyToList(sourcelist, PermissionVo.class);
        //已配置菜单
        List<RolePermissionPo> rpids = rolePermissionMapper.selectList(new LambdaQueryWrapper<RolePermissionPo>()
                .in(RolePermissionPo::getRid, roleId));
        List<PermissionPo> permissionPoList = permissionMapper.selectBatchIds(rpids.stream()
                .map(RolePermissionPo::getPid).collect(Collectors.toList()));
        voList.stream().filter(permissionPo -> {
            if (!permissionPoList.stream()
                    .filter(p -> p.getId().equals(permissionPo.getId())).toList().isEmpty()) {
                permissionPo.setUsed(true);
            }
            return false;
        }).toList();
        //第1级菜单
        return getTreePermission(voList);
    }

    @Override
    public Integer addRolePermission(Integer roleId, List<Integer> permissionId) {
        rolePermissionMapper.delete(new LambdaQueryWrapper<RolePermissionPo>().eq(RolePermissionPo::getRid, roleId));
        return rolePermissionMapper.insert(permissionId.stream().map(pid -> new RolePermissionPo(roleId, pid)).toList()).size();
    }

    @Override
    public Integer delRolePermission(Integer id) {
        return rolePermissionMapper.deleteById(id);
    }

    @Override
    public Integer addRole(RoloVo roloVo) {
        return 0;
    }

    @Override
    public List<RolePo> selectRoleList(Integer userId) {
        List<UserRolePo> userRolePos = userRoleMapper.selectList(new LambdaQueryWrapper<UserRolePo>()
                .eq(UserRolePo::getUid, userId));
        if (!userRolePos.isEmpty()) {
            List<Integer> rIds = userRolePos
                    .stream().map(UserRolePo::getRid).toList();
            return roleMapper.selectList(new LambdaQueryWrapper<RolePo>().in(RolePo::getId, rIds));
        }
        return null;
    }

    @Override
    public Integer delRole(Integer id) {
        roleMapper.deleteById(id);
        rolePermissionMapper.delete(new LambdaQueryWrapper<RolePermissionPo>().eq(RolePermissionPo::getRid, id));
        return id;
    }

    @Override
    public Integer updateRole(RoloVo roloVo) {
        return 0;
    }

    @Override
    public Integer UpdateRolePermission(Integer roleId, List<Integer> permissionId) {
        rolePermissionMapper.delete(new LambdaQueryWrapper<RolePermissionPo>().eq(RolePermissionPo::getRid, roleId));
        return rolePermissionMapper.insert(permissionId.stream().map(pid -> new RolePermissionPo(roleId, pid)).toList()).size();
    }

    @Override
    public Integer addPermission(PermissionPo permissionPo) {
        return null;
    }

    @Override
    public Integer delPermission(Integer id) {
        return null;
    }

    @Override
    public Integer updatePermission(PermissionPo permissionPo) {
        return null;
    }


    private static List<PermissionVo> getTreePermission(List<PermissionVo> permissionPoList) {
        //第1级菜单
        List<PermissionVo> parent = permissionPoList.stream().filter(permissionPo -> permissionPo.getIsMenu() == 1)
                .filter(permissionPo -> permissionPo.getParentId() == 0).sorted(Comparator.comparing(PermissionVo::getSortNum)).toList();
        //第2级菜单
        List<PermissionVo> resultList = new ArrayList<>();
        parent.forEach(permissionPo -> {
            PermissionVo vo = new PermissionVo();
            BeanUtil.copyProperties(permissionPo, vo);
            vo.setChildren(permissionPoList.stream()
                    .filter(permissionPo1 -> Objects.equals(permissionPo1.getParentId(), permissionPo.getId()))
                    .map(permissionPo1 -> {
                        PermissionVo child = new PermissionVo();
                        BeanUtils.copyProperties(permissionPo1, child);
                        return child;
                    })
                    .sorted(Comparator.comparing(PermissionVo::getSortNum))
                    .toList());
            resultList.add(vo);
        });
        return resultList;
    }

}
